using System;
using System.IO;
using CodePlex.TfsLibrary.ObjectModel;
using CodePlex.TfsLibrary.RepositoryWebSvc;

namespace CodePlex.CodePlexClientLibrary
{
    [Command("syncup", "Reconcile off-line changes with server", AltName = "su", MaxArgs = 0, UsageSummary = "[options]",
        UsageDescription = @"The syncup command reconciles your off-line changes with the server in
preparation for a commit operation. Syncup performs three actions:

- Look for locally deleted files and folders and mark them as deleted
- Runs update against the server
- Look for locally added files and folders and mark them as added

Syncup prompts before each add operation and allows the user to choose among
the options of adding, ignoring, and deleting the item (as well as an option
to 'add all'. If /non-interactive is specified, then syncup assumes the user
wants to add all items that are found.

Syncup works recursively on the current directory.

The first column shows local changes:
  +  Locally marked for Add
  -  Locally marked for Delete
  *  Locally reverted

The second column shows server updates:
  A  Server Added
  C  Server Conflicted
  D  Server Deleted
  M  Server Merged automatically
  R  Server Renamed
  U  Server Updated")]
    public class SyncupCommand : AuthenticatedCommand
    {
        bool alwaysAdd = false;
        bool verbose;

        [Option("verbose", "display verbose information", ShortName = "v")]
        public bool Verbose
        {
            get { return verbose; }
            set { verbose = value; }
        }

        static string ActionToLetter(SyncupAction action)
        {
            switch (action)
            {
                case SyncupAction.LocalAdded:
                    return "+   ";
                case SyncupAction.LocalDeleted:
                    return "-   ";
                case SyncupAction.LocalReverted:
                    return "*   ";
                case SyncupAction.ServerAdded:
                    return "   A";
                case SyncupAction.ServerConflicted:
                    return "   C";
                case SyncupAction.ServerDeleted:
                    return "   D";
                case SyncupAction.ServerMerged:
                    return "   M";
                case SyncupAction.ServerUpdated:
                    return "   U";
            }

            return action.ToString();
        }

        public override void Execute()
        {
            alwaysAdd = NonInteractive;

            Engine.Syncup(Directory.GetCurrentDirectory(), OnBeforeAddItem, OnSyncupItem);
        }

        bool OnBeforeAddItem(SourceItem item)
        {
            if (alwaysAdd)
                return true;

            Console.WriteLine(CodePlexClientUtil.GetRelativePath(Directory.GetCurrentDirectory(), item.LocalName));
            Console.Write("  Add to source control? [Y]es, [N]o, [D]elete, [A]dd all ? (N) ");
            string answer = Console.ReadLine().ToLowerInvariant();

            if (answer == "a")
                alwaysAdd = true;
            else if (answer == "d")
            {
                if (item.ItemType == ItemType.File)
                    File.Delete(item.LocalName);
                else
                    Directory.Delete(item.LocalName, true);
            }

            return (answer == "y" || answer == "a");
        }

        static void OnSyncupItem(SourceItem item,
                                 SyncupAction actionTaken,
                                 SourceItemResult result)
        {
            if (result != SourceItemResult.S_Ok && result != SourceItemResult.S_ForcedDelete)
                ConsoleUtil.PrintCommandError(item.LocalName, result);
            else
            {
                string relativePath = CodePlexClientUtil.GetRelativePath(Directory.GetCurrentDirectory(), item.LocalName);

                switch (actionTaken)
                {
                    case SyncupAction.None:
                        Console.WriteLine("Won't clobber existing {0}", relativePath);
                        break;

                    default:
                        Console.WriteLine("{0}  {1}", ActionToLetter(actionTaken), relativePath);
                        break;
                }
            }
        }
    }
}